/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 *
 */

import path from 'path';
import * as util from 'util';

import { getAlignTarget } from '@ohos/hvigor/src/base/util/task-util.js';

import { findTargetProduct } from '../../common/find-target-product.js';
import { getBuildRoot } from '../../common/hvigor-extra-config-info.js';
import { ModulePathInfoIml } from '../../common/iml/module-path-info-iml.js';
import { ModuleType } from '../../enum/module-type-enum.js';
import { CoreModuleModelImpl } from '../../model/module/core-module-model-impl.js';
import { ModuleModel } from '../../model/module/module-model.js';
import { ProjectModel } from '../../model/project/project-model.js';
import { ModuleBuildProfile } from '../../options/build/module-build-profile.js';
import { ProjectBuildProfile } from '../../options/build/project-build-profile.js';
import { OhosLogger } from '../../utils/log/ohos-logger.js';
import { ModuleTargetData } from '../data/hap-task-target-data.js';
import { FullStatus, Status } from './status.js';
import { TaskService } from './task-service.js';

import ProductBuildOpt = ProjectBuildProfile.ProductBuildOpt;
import ModuleTargetBuildOpt = ModuleBuildProfile.ModuleTargetBuildOpt;

import { ModuleTargetImpl } from '../../plugin/context/impl/module-target-impl.js';
import { Target } from '../../plugin/context/plugin-context.js';
import { DependencyManager } from '../../project/dependency/dependency-manager.js';
import { TargetUtils } from '../../utils/target-utils.js';
import { InjectUtil } from '../../utils/inject-util.js';
import { ServiceLocator } from '../../arkts-evolution/service/service-locator.js';


const _log = OhosLogger.getLogger('Hvigor-module-service');

/**
 * 基于持久化module的模型层提供的数据，经过处理后,提供给打包hap任务流需要使用的服务和数据
 *
 * @since 2022/1/20
 */
export class ModuleTaskService extends TaskService {
  private readonly _moduleModel: ModuleModel;
  private readonly _status: FullStatus;
  private readonly _targetDataSet: Set<[ModuleTargetData, boolean]>;
  private _targets: Target[];

  constructor(projectModel: ProjectModel, moduleModel: ModuleModel, dependencyManager: DependencyManager, isFaMode: boolean) {
    super(moduleModel.getModule(), projectModel, dependencyManager, isFaMode);
    this._moduleModel = moduleModel;
    this._targetDataSet = new Set<[ModuleTargetData, boolean]>();
    this._targets = [];
    this._status = new FullStatus(this.initTargetData());
  }

  public getModuleModel(): CoreModuleModelImpl {
    return this._moduleModel as CoreModuleModelImpl;
  }

  public getTargetDataSet(): Set<[ModuleTargetData, boolean]> {
    return this._targetDataSet;
  }

  public getTargets(): Target[] {
    return this._targets;
  }

  public isArkModule(): boolean {
    return this._moduleModel.isArkModule();
  }

  /**
   * 返回该service对应模块关联的entry模块
   */
  public getRelatedEntryModules(): string[] | undefined {
    return this._moduleModel!.getRelatedEntryModules() ?? undefined;
  }

  /**
   * 模块级build-profile.json5中模板不再提供entryModules字段且schema将其标识为废弃
   * 检查feature模块配置文件中entryModules字段
   */
  public static checkEntryModules(moduleType: string, relatedEntryModules: string[] | undefined): boolean {
    return moduleType === ModuleType.Feature && relatedEntryModules !== undefined && relatedEntryModules.length !== 0;
  }

  public hasLiteDevice(): boolean {
    return this._moduleModel.getDeviceTypes()?.some((deviceType) => {
      return deviceType === 'liteWearable' || deviceType === 'smartVision';
    });
  }

  /**
   * 初始化hap模块打包流的target数据集合, 并返回对应所有需要打包targets的状态
   */
  private initTargetData(): Status[] {
    const targets = this._moduleModel.getTargetOptions();
    const curModuleConfigTargets: string[] = TargetUtils.computeTargets(this._projectModel.getModuleSpecificTargets().get(this._moduleModel!.getName()), targets);
    const buildRoot = getBuildRoot();
    const modulePath = this._moduleModel.getProjectDir();

    // 不允许配置BuildRoot为modulePath以外的路径，即不允许以..开头
    if (path.normalize(path.relative(modulePath, path.resolve(modulePath, buildRoot))).startsWith('..')) {
      _log.printErrorExit('INVALID_BUILDROOT_VALUE', [buildRoot]);
    }

    const targetProduct: ProductBuildOpt = findTargetProduct(this._projectModel!);
    const statusArr: Status[] = [new Status(this._moduleModel.getProfileOpt())];

    targets.forEach((target: ModuleTargetBuildOpt) => {
      const targetName: string = target.name;
      const needPack: boolean = this.targetNeedPack(targetProduct, targetName, curModuleConfigTargets);
      const pathInfo: ModulePathInfoIml = new ModulePathInfoIml(this._moduleModel, targetName, targetProduct.name, buildRoot);

      // 注册modulePathInfoService
      ServiceLocator.registerModulePathInfoService(targetProduct.name, this._moduleModel.getModule().getName(), targetName, pathInfo);

      // 需要打包的才添加
      if (needPack) {
        this._targets.push(new ModuleTargetImpl(target, pathInfo, this._projectModel, this._moduleModel));
      }
      const moduleTargetData = new ModuleTargetData(this._moduleModel!, target, pathInfo, targetProduct);
      this._targetDataSet.add([moduleTargetData, needPack]);
      statusArr.push(moduleTargetData.getTargetStatus());
    });
    return statusArr;
  }

  /**
   * 根据name返回target信息，若没有则返回undefined
   *
   * @param {string} targetName
   * @returns {ModuleTargetData | undefined}
   */
  public findTargetDataByName(targetName: string): ModuleTargetData | undefined {
    for (const value of this._targetDataSet.values()) {
      const targetData = value[0];
      if (targetData.getTargetName() !== targetName) {
        continue;
      }
      return targetData;
    }
    return undefined;
  }

  private targetNeedPack(targetProduct: ProductBuildOpt, targetName: string, curModuleConfigTargets: string[]): boolean {
    let needPack = false;

    if (curModuleConfigTargets.indexOf(targetName) > -1) {
      needPack = true;
    }

    if (curModuleConfigTargets.indexOf('all') > -1) {
      // 默认不配置target时,不打包ohosTest的包
      needPack = targetName !== 'ohosTest';
    }

    // 如果命令行存在onDeviceTest参数则默认放开ohosTest限制
    if (InjectUtil.isDeviceTest()) {
      needPack = targetName === 'ohosTest' || targetName === 'default';
    }

    return checkHasTargetApplyProduct(this._moduleModel, targetName, targetProduct.name) && needPack;
  }
}

/**
 * 校验一个Module的指定的TargetName对应的Target是否applyTo了指定的targetProduct,即默认的default或者命令行中执行的target
 *
 * @param {ModuleModel} moduleModel
 * @param {string} targetName
 * @param {string} targetProductName
 * @return {boolean}
 */
export function checkHasTargetApplyProduct(moduleModel: ModuleModel, targetName: string, targetProductName: string): boolean {
  // alignTarget开关开启后也不用进行校验
  if (moduleModel.isHarModule() || getAlignTarget()) {
    return true;
  }

  const projectModel = moduleModel.getParentProject() as ProjectModel;
  let products = projectModel?.getTargetApplyProducts(moduleModel!.getName()!, targetName);

  // 如果没有配置applyToProducts则默认是default
  if (products === undefined) {
    products = ['default'];
  }
  const allProductNames = projectModel.getProductNames();
  const hasConfigErrorProduct = products.some((value) => {
    return !allProductNames.includes(value);
  });
  if (hasConfigErrorProduct) {
    _log
      .printErrorExit(
        'INVALID_PRODUCT_FOR_TARGET',
        [targetName, projectModel.getProfilePath()],
        [[targetName, util.format(products)]]
      );
  }

  return products.includes(targetProductName);
}
